/**
 * Copyright (c) 2015-2020, wss 王山山
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.wss.utils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import com.wss.utils.annotations.NotNull;
import com.wss.utils.exception.ReflectionException;

/**
 * 反射工具类
 * 
 * @author wss
 *
 */
public final class ReflectionUtil {
	/**
	 * 获取类上的指定注解
	 * 
	 * @param targetClass		目标类
	 * @param annotationClass	注解的Class
	 * @return					以Optional<T>形式返回注解类的对象
	 */
	public static <T extends Annotation> Optional<T> getAnnotationByType(@NotNull Class<?> targetClass, 
			@NotNull Class<T> annotationClass) {
		
		Objects.requireNonNull(targetClass);
		Objects.requireNonNull(annotationClass);
		
		T t = targetClass.getAnnotation(annotationClass);
		return Optional.ofNullable(t);
	}
	
	/**
	 * 根据全类名动态加载类
	 * 
	 * @param className		全类名
	 * @return				加载之后的类
	 */
	public static Class<?> loadClass(@NotNull String className) {
		Objects.requireNonNull(className);
		
		try {
			return Class.forName(className);
		} catch (ClassNotFoundException e) {
			throw new ReflectionException(e);
		}
	}
	
	public static Field[] getDeclaredFields(Class<?> clazz) {
		return clazz.getDeclaredFields();
	}
	
	public static List<String> getFieldNames(Class<?> clazz) {
		Field[] fields = getDeclaredFields(clazz);
		return Arrays.stream(fields).map(e -> e.getName()).collect(Collectors.toList());
	}
	
	public static <T> T newInstance(Class<T> clazz) {
		try {
			return clazz.newInstance();
		} catch (ReflectiveOperationException e) {
			throw new ReflectionException(e);
		}
	}
	
	/**
	 * 判断两个类是否是继承关系
	 * 
	 * @param parentClass		父类Class
	 * @param subClass			子类Class
	 * @return					true: 是继承关系，false: 不是继承关系
	 */
	public static boolean isInheritRelationship(Class<?> parentClass, Class<?> subClass) {
		return parentClass.isAssignableFrom(subClass);
	}
	
	public static<T extends Annotation> boolean hasAnnotation(Class<?> targetClass, Class<T> annotationClass) {
		return getAnnotationByType(targetClass, annotationClass).isPresent();
	}
}
